import { _decorator, CircleCollider2D, Collider2D, Color, Component, Contact2DType, director, Label, math, Node, PhysicsSystem2D, sys, System, tween, Vec2, Vec3 } from 'cc';
import { Drawlayer, UICtrl } from '../Ctrl/UICtrl';
import GameEventMgr, { GameEvent } from '../Model/GameEventMgr';
import { Unit, UnitEvent } from './Unit';
import { Global, UnitType } from '../Util/Global';
import { UnitPlanet } from './UnitPlanet';
import { LevelUpCom } from './Component/LevelUpCom';
import { Tools } from '../Util/Tools';
const { ccclass, property } = _decorator;

interface PlanetTrackData {
    planet: UnitPlanetBase;
    circleRadius: number;//轨道长度
    circleGravity: number;
    rotationDir: number;//旋转方向
    linearV: number;//圆周线性速度
    // trackPos:Vec3;//所在轨道位置
}

/**行星基类 */
@ccclass('UnitPlanetBase')
export class UnitPlanetBase extends Unit {
    @property(Label)
    public messageLabel: Label = null;
    @property({ displayName: "减速最低维持速度" })
    minStandSpeed: number = 1.5;
    @property({ displayName: "是否固定" })
    public lockPos: boolean = false;
    @property({ visible: true })
    public collider: CircleCollider2D = null;

    /**来自其他星球的引力影响 */
    protected otherPlanetImpactList: UnitPlanetBase[] = [];
    /**受我的星球的引力影响 */
    protected selfPlanetImpactList: UnitPlanetBase[] = [];

    private _bigPlanetCount: number = 0;
    get bigStarCount() {
        return this._bigPlanetCount;
    }

    public trigger: CircleCollider2D = null;

    /**固定轨道卫星的锚定对象 */
    public _forceTrackTarget: UnitPlanetBase = null;
    /**固定轨道卫星的锚定对象 */
    get forceTrackTarget() {
        return this._forceTrackTarget;
    }
    /**固定轨道卫星的锚定对象 */
    set forceTrackTarget(value) {
        if (value != this._forceTrackTarget && this._forceTrackTarget) {
            this.trackData = null;
            this._forceTrackTarget.RemoveSatellite(this);
        }
        if (value == null) {
            this.trackData = null;
            if (this._bigPlanetCount > 0) {
                value = this.FilterOtherImpactPlanet_One((target) => {
                    return target.unitType > this.unitType;
                })
            }
        }
        this._forceTrackTarget = value;
        this.draw_fixedTrack_gravity_Line = value != null;
    }

    /**是否绘制固定轨道的引力线 */
    public draw_fixedTrack_gravity_Line: boolean = true;
    /**设置允许固定轨道捕获 */
    public SetFixedTrackMoveTarget(value: UnitPlanetBase, drawLine: boolean = true) {
        this.forceTrackTarget = value;
        this.draw_fixedTrack_gravity_Line = drawLine;
    }

    protected frameGravitySpeed: number = 0;

    protected onDisable(): void {
        super.onDisable();

        this.otherPlanetImpactList = [];
        this.selfPlanetImpactList = [];
        this._bigPlanetCount = 0;
        this._forceTrackTarget = null;
        this.standTime = 1;
        this.isGravityInpact = false;
        this.satellitesMap.clear();
        this.trackData = null;
        this.draw_fixedTrack_gravity_Line = true;
        this.oneTrack = false;
        this.track_circle_priority = 0;

        this._RBVFrame_MoveAdd.set(0, 0);
        this._RBVFrame_GravityAdd.set(0, 0);
    }

    /**添加其他对我有引力影响的行星 */
    public AddPlanetGravityImpact(planet: UnitPlanetBase) {
        if (!this.otherPlanetImpactList.includes(planet)) {
            this.otherPlanetImpactList.push(planet);
            planet.addSelfImpactPlanet(this);//自己作为被影响方记录其中
            if (planet.unitType > this.unitType) {
                this._bigPlanetCount++;
            }

            this.dispatch(UnitEvent.EnterOtherPlanetGravity, planet);
        }
    }

    public RemovePlanetGravityImpact(planet: UnitPlanetBase) {
        let indexToRemove = this.otherPlanetImpactList.indexOf(planet);
        if (indexToRemove !== -1) {
            this.otherPlanetImpactList.splice(indexToRemove, 1);
            planet.RemoveSelfImpactPlanet(this);
            if (planet.unitType > this.unitType) {
                this._bigPlanetCount--;
            }

            this.dispatch(UnitEvent.EixtOtherPlanetGravity, planet);
        }
        if (planet == this.forceTrackTarget) {//如果是自身的锚定对象
            planet.RemoveSatellite(this);
            this.forceTrackTarget = null;
        }
    }

    protected addSelfImpactPlanet(planet: UnitPlanetBase) {
        if (!this.selfPlanetImpactList.includes(planet)) {
            this.selfPlanetImpactList.push(planet);

            this.dispatch(UnitEvent.EnterSelfPlanetGravity, planet);
        }
    }

    protected RemoveSelfImpactPlanet(planet: UnitPlanetBase) {
        let indexToRemove = this.selfPlanetImpactList.indexOf(planet);
        if (indexToRemove !== -1) {
            this.selfPlanetImpactList.splice(indexToRemove, 1);

            this.dispatch(UnitEvent.EixtSelfPlanetGravity, planet);
        }
    }

    /**从被我引力影响的天体中找出目标 */
    public FilterSelfImpactPlanet_One<T extends UnitPlanetBase>(call: (planet: UnitPlanetBase) => boolean) {
        for (let i = 0; i < this.selfPlanetImpactList.length; i++) {
            let planet = this.selfPlanetImpactList[i];
            if (call(planet)) {
                return planet as T;
            }
        }
        return null;
    }

    /**从影响我的天体中找出目标 */
    public FilterOtherImpactPlanet_One<T extends UnitPlanetBase>(call: (planet: UnitPlanetBase) => boolean) {
        for (let i = 0; i < this.otherPlanetImpactList.length; i++) {
            let planet = this.otherPlanetImpactList[i];
            if (call(planet)) {
                return planet as T;
            }
        }
        return null;
    }

    /**从影响我的天体中找出所有符合条件的目标 */
    public FilterOtherImpactPlanet_All<T extends UnitPlanetBase>(call: (planet: UnitPlanetBase) => boolean): T[] {
        let all = []
        for (let i = 0; i < this.otherPlanetImpactList.length; i++) {
            let planet = this.otherPlanetImpactList[i];
            if (call(planet)) {
                all.push(planet as T);
            }
        }
        return all;
    }

    protected start() {
        super.start();
        this.messageLabel.node.active = false;
        this.messageLabel.string = '';
        if (this.unitType >= UnitType.UnitSun) {
            this._bigPlanetCount++;
        }

        // 监听传感器碰撞事件
        this.collider.on(Contact2DType.BEGIN_CONTACT, this.onColliderEnter, this);

        for (let co of this.colliders) {
            if (co.tag == 1) {
                this.trigger = co as CircleCollider2D;

                //监听传感器碰撞事件
                this.trigger.on(Contact2DType.BEGIN_CONTACT, this.onTriggerEnter, this);
                this.trigger.on(Contact2DType.END_CONTACT, this.onTriggerExit, this);
                break;
            }
        }
        this.trigger.radius = this.alertFieldRadius;
    }

    private _worldPos = new Vec3(); //messageLabel专用
    protected _updateLogic(dt: number): void {
        super._updateLogic(dt);
        this.node.getWorldPosition(this._worldPos);
        this.messageLabel.node.active = this.isInScreenPos;
        if (sys.isBrowser) {
            this.messageLabel.string = `(${Math.floor(this._worldPos.x)},${Math.floor(this._worldPos.y)},${Math.floor(this.speed)})`;
        }
        // else if (!Global.isIOSDevices) {//ios会卡
        //     this.messageLabel.string = `${Math.floor(this.speed)}`;
        // }
    }

    protected onDestroy(): void {

        this.trigger.off(Contact2DType.BEGIN_CONTACT, this.onTriggerEnter, this);
        this.trigger.off(Contact2DType.END_CONTACT, this.onTriggerExit, this);

        this.collider.off(Contact2DType.BEGIN_CONTACT, this.onColliderEnter, this);
    }

    protected checkMaxLimitVelocity() {
        let maxSp = this.maxSpeed;
        if (this.frameGravitySpeed > maxSp) {
            maxSp = this.maxSpeed + this.frameGravitySpeed;
        }
        this.frameGravitySpeed = 0;

        if (this._frameMaxSpeed > maxSp) {
            maxSp = this._frameMaxSpeed;
        }

        if (this.speed > maxSp) {//暂时设置最大速度
            let v = this.rigBody.linearVelocity.clone().normalize().multiplyScalar(maxSp);
            this.rigBody.linearVelocity = v;
        }
    }

    /**每次更改速度时，将这个赋值1以取消每帧的刹车效果 */
    public standTime = 1;

    protected _lateUpdateLogic(dt: number): void {
        super._lateUpdateLogic(dt);

        if (this.otherPlanetImpactList.length <= 0) {//附近没有其他行星
            this.parentUnit = null;
            if (this.isGravityInpact) {
                this.isGravityInpact = false;
                GameEventMgr.Dispatch(GameEvent.OnPlanetNoGravityInpact, this);
            }
        }
        else {
            this.isGravityInpact = true;
        }

        if (this.lockPos) {
            this.rigBody.linearVelocity = Vec2.ZERO.clone();
        }
        else {
            this.lateUpdateLogic(dt);
        }
    }

    /**替代lateUpdate，不会影响下基类的lateUpdate逻辑 */
    protected lateUpdateLogic(dt: number) {

        //如果有环绕对象进行绑定环绕
        if (this.forceTrackTarget && this.FixedTrackMove(dt)) {
            this.UpdateBiggerTargetPlanetForce();
        }
        else {
            this.UpdateOtherPlanetForce();
        }

        this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(this._RBVFrame_GravityAdd);
        this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(this._RBVFrame_MoveAdd);
        this.Stand(dt, 0.001, this.minStandSpeed);
    }

    protected lateUpdate(dt: number): void {
        super.lateUpdate(dt);
        this._RBVFrame_MoveAdd.set(0, 0);
        this._RBVFrame_GravityAdd.set(0, 0);
    }

    /**
     * 检测并强制并入行星轨道 直接赋予环绕速度 后续继续引力模拟
     * @param planet 检测的天体
     * @param forceToTrack 是否强制
     */
    CheckPlanetOnTrank(planet: UnitPlanetBase, forceToTrack = false) {
        if (this.lockPos) {
            return;
        }
        let planetV = planet.rigBody.linearVelocity;
        let sunDir = planet.GetDirToOther(this);

        planetV = planetV.normalize();
        let sunDir2 = this.ToVec2(sunDir).normalize();
        let cos = planetV.dot(sunDir2);

        if (planet.speedS < 1 || Math.abs(cos) <= 0.8) {//“几乎”垂直

            let trackData = this.CalculateCircleTrackData(planet);

            //不断通过切线方向计算出下一帧应该旋转到的位置
            let radiusVector = this.ToVec2(this.GetDirToOther(trackData.planet));
            let targetPos = this.unitWorldPos;
            let tangentDirection: Vec2 = new Vec2(-radiusVector.y * trackData.rotationDir, trackData.rotationDir * radiusVector.x).normalize();
            // if (cos < 0) {//切线反了
            //     tangentDirection.multiplyScalar(-1);
            // }
            // let tangentDirection: Vec2 = new Vec2(-radiusVector.y, radiusVector.x).normalize();
            let radiusDirection = this.ToVec3(radiusVector).normalize();

            targetPos = targetPos.add(radiusDirection.clone().multiplyScalar(trackData.circleRadius));

            tangentDirection.multiplyScalar(trackData.linearV);
            targetPos.add(this.ToVec3(tangentDirection));

            if (planet.unitType <= this.unitType || forceToTrack) {
                let allowable = true;
                if (planet == Global.gameManager.playerUnit) {
                    let levelCom = planet.getComponent(LevelUpCom);
                    if (levelCom && levelCom.level > 1) {
                        allowable = false;
                    }
                    //2级星球暂不能被强制捕获
                }

                //已经被其他恒星捕获过就忽略
                if (planet.parentUnit != null || planet.forceTrackTarget) {
                    allowable = false;
                }

                if (allowable) {

                    let dr = trackData.circleRadius - this.alertFieldRadius;
                    if (dr > 0 && dr < 50) {//从外部进入
                        let pos = this.unitWorldPos.add(radiusDirection.clone().multiplyScalar(this.alertFieldRadius - 10)).clone();
                        this.scheduleOnce(() => {
                            //cocos在使用刚体组件时，和update不是同步的，也就是说你在update中改了刚体会影响的属性，会被刚体覆盖！可能还会报错！
                            //比如把active设置false，刚体就会报错，要延后执行
                            if (trackData.planet.isValid) {
                                // GameEventMgr.Dispatch(GameEvent.LogGameMessage, "捕获！");
                                trackData.planet.node.setWorldPosition(pos);
                                let distance = pos.subtract(planet.unitWorldPos).length();
                                if (distance > 100) {
                                    GameEventMgr.Dispatch(GameEvent.LogGameMessage, "捕获异常！");
                                }
                            }
                        }, 0);
                    }

                    // 有概率捕获的瞬间就碰撞销毁了！记得回来修复下
                    trackData.planet.MoveTo(targetPos, true);//移动到该位置并覆盖其速度
                }
            }
            // else if (planet.unitType == UnitType.UnitSun && this.unitType == UnitType.UnitSun && planet.DistanceOther(this) < 100) {//避让

            //     GameEventMgr.Dispatch(GameEvent.LogGameMessage, "恒星捕获避让！");
            //     trackData.planet.rigBody.linearVelocity = trackData.planet.rigBody.linearVelocity.add(tangentDirection.multiplyScalar(trackData.linearV));
            //     trackData.planet.standTime = 1;
            // }
            // trackData.planet.rigBody.linearVelocity = tangentDirection.multiplyScalar(trackData.linearV);
            // trackData.planet.standTime = 1;
        }
    }

    protected isGravityInpact: boolean = false;
    /**更新其他行星对自己的引力影响 */
    protected UpdateOtherPlanetForce(otherPlanetList?: UnitPlanetBase[]) {
        otherPlanetList = otherPlanetList || this.otherPlanetImpactList;

        let maxBigPlanet: UnitPlanetBase[] = [this];
        // let sunCount = this.unitType >= UnitType.Sun ? 1 : 0;
        for (let i = 0; i < otherPlanetList.length; i++) {
            let planet: UnitPlanetBase = otherPlanetList[i];

            if (planet == null || !planet.isValid) {
                // 删除
                otherPlanetList.splice(i, 1);
                i--;
                continue;
            }

            let distance = this.DistanceOther(planet);

            //找到星级最大的
            if (planet.unitType >= maxBigPlanet[0].unitType) {
                if (planet.unitType > maxBigPlanet[0].unitType) {
                    //且大一级则丢弃之前的
                    maxBigPlanet.length = 0;
                }
                maxBigPlanet.unshift(planet);
            }

            let gravityS = planet.CalculateGravityWithOther(this);//其他行星对自身的影响

            // 获取物理系统的时间步长
            let gravity = gravityS * PhysicsSystem2D.instance.fixedTimeStep * 1.38;

            //增加一个防撞击修正，过于靠近时，忽略引力影响
            let avoidance = false;//是否避让

            let beforeCond = false;
            let checkDis = Math.min(250, 1000 * gravity);//避让半径
            //恒星级且只会避让同级或比自己大一级的行星
            let type_ok = Tools.getEnumIndex(UnitType, planet.unitType) - Tools.getEnumIndex(UnitType, this.unitType) <= 1;
            type_ok = type_ok || (this.unitType < UnitType.UnitSun && planet.unitType > this.unitType);

            beforeCond = this._bigPlanetCount > 1 && type_ok && distance < checkDis;
            // beforeCond = beforeCond && !this.forceTrackTarget;
            if (beforeCond) {

                let disVec = this.GetDirToOther(planet);
                let planetV = this.rigBody.linearVelocity.normalize();
                let disVN = disVec.clone().normalize();
                let cosD = this.ToVec2(disVN).dot(planetV);
                if (cosD > 0.7 || distance < this.speedS) {//相当于直接冲向对方，修改方向
                    let tangentDirection: Vec2 = new Vec2(-disVec.y, disVec.x).normalize();
                    let cos = planetV.dot(tangentDirection.clone());

                    //尽量避免特殊情况->并排加速
                    let otherPlanetV = planet.rigBody.linearVelocity.normalize();
                    if (otherPlanetV.dot(planetV) > 0.5) {
                        //并排加速情况下就不用更具切线与速度的夹角选择正负切线了
                        //这样就可以错开
                    }
                    else if (cos < 0) {//切线反了
                        tangentDirection.multiplyScalar(-1);
                        if (sys.isBrowser && <UnitPlanet>planet == Global.gameManager.playerUnit) {
                            GameEventMgr.Dispatch(GameEvent.LogGameMessage, '避让方向反向！')
                        }
                    }
                    if (true) {
                        //玩家就将其抛出
                        if (cosD < 0.5) {
                            this._RBVFrame_GravityAdd.add(planetV.multiplyScalar(gravity));
                            this.maxSpeed_currentFame = 100;
                            this.fixedTrackInterval = 3;
                        }
                        else {
                            this._RBVFrame_GravityAdd.add(tangentDirection.multiplyScalar(gravity));
                        }
                    }
                    else {
                        let maxAvoidance = Math.min(gravity, 1000 / this.mass);//最大避让速度
                        this._RBVFrame_GravityAdd.add(tangentDirection.multiplyScalar(maxAvoidance))
                    }
                    // this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(tangentDirection.multiplyScalar(maxAvoidance));

                    // GameEventMgr.Dispatch(GameEvent.LogGameMessage, "避让！");
                    avoidance = true;
                }

            }

            if (!avoidance) {

                let disVec = this.GetDirToOther(planet);//自己指向其他
                let force = disVec.clone().normalize();
                force.multiplyScalar(gravity);
                this._RBVFrame_GravityAdd.add(this.ToVec2(force));
                // this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(this.ToVec2(force));
            }

            this.frameGravitySpeed = Math.sqrt(gravityS * this.DistanceOther(planet)) * 0.2;
        }

        if (otherPlanetList.length > 0) {
            this.standTime = 1;
        }

        maxBigPlanet.sort((a, b) => {
            return a.node.getSiblingIndex() - b.node.getSiblingIndex();
        });

        let targetPlanet = maxBigPlanet[0];
        // let near = this.DistanceOther(bigPlanet);
        for (let i = 0; i < maxBigPlanet.length; i++) {
            let planet = maxBigPlanet[i];
            if (planet == this) {//发现自己就在其中
                if (i + 1 >= maxBigPlanet.length) {
                    targetPlanet = maxBigPlanet[0];
                }
                else {
                    targetPlanet = maxBigPlanet[i + 1];
                }
                break;
            }
            else {//否则取最近的
                targetPlanet = planet.DistanceOther(this) < targetPlanet.DistanceOther(this) ? planet : targetPlanet;
            }
        }

        if (targetPlanet.unitType > this.unitType) {
            this.parentUnit = targetPlanet;
        }
        // let endPos = this.transform.convertToNodeSpaceAR(targetPlanet.unitWorldPos);
        if (!this.forceTrackTarget) {
            UICtrl.LineRenderer(this.unitWorldPos, targetPlanet.unitWorldPos, Color.WHITE, Drawlayer.Game);
        }

    }

    /**卫星 */
    protected satellitesMap: Map<UnitPlanetBase, PlanetTrackData> = new Map();

    public FindOneSatellite(unitType: UnitType) {
        for (let [k, v] of this.satellitesMap) {
            if (k.unitType == unitType) {
                return k;
            }
        }
        return null;
    }

    public AddSatellite(planet: UnitPlanetBase, trackData: PlanetTrackData): boolean {
        if (!this.satellitesMap.has(planet)) {
            this.satellitesMap.set(planet, trackData);
            planet.trackData = trackData;
            planet.fixedTrackInterval = 3;
            return true;
        }

        return false;
    }

    public RemoveSatellite(planet: UnitPlanetBase) {
        if (this.satellitesMap.has(planet)) {
            this.satellitesMap.delete(planet);
            planet.trackData = null;
            planet.fixedTrackInterval = 3;
            return true;
        }

        return false;
    }

    /**只受目标引力影响、忽略其他行星引力 */
    protected UpdateTargetPlanetForce(dt: number) {
        if (!this.forceTrackTarget || this.forceTrackTarget.death) {
            return;
        }
        this.standTime = 1;

        let planet: UnitPlanetBase = this.forceTrackTarget;
        let gravityS = planet.CalculateGravityWithOther(this);//其他行星对自身的影响
        let gravity = gravityS * PhysicsSystem2D.instance.fixedTimeStep * 1.38;

        let disVec = this.GetDirToOther(planet);//自己指向其他
        let force = disVec.normalize();
        force.multiplyScalar(gravity);
        this._RBVFrame_GravityAdd.add(this.ToVec2(force));
        // this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(this.ToVec2(force));

        this.parentUnit = planet;
        UICtrl.LineRenderer(this.unitWorldPos, planet.unitWorldPos, Color.WHITE, Drawlayer.Game);
    }

    /**固定的轨道数据 */
    public trackData: PlanetTrackData = null;
    public oneTrack: boolean = false;
    /**环绕轨道优先策略 */
    protected track_circle_priority: number = 0;
    get track_priority() {
        return this.track_circle_priority;
    }

    /**设置固定环绕轨道捕获策略 */
    SetFixedTrackStrategy(oneTrack: boolean, circle_priority: number) {
        this.oneTrack = oneTrack;
        this.track_circle_priority = circle_priority;
        this.satellitesMap.forEach((v, k) => {
            k.trackData = null;//重新捕获
            k.fixedTrackInterval = 0;//立即刷新捕获
        });
        this.satellitesMap.clear();
    }

    /**捕获间隔 当该值大于0时无法再次捕获 */
    public fixedTrackInterval: number = 0;
    /**
     * 尝试环绕目标、固定半径的环绕轨道
     * @returns 环绕成功
     */
    FixedTrackMove(dt: number): boolean {//被撞击应该增加失衡设定、暂时不能固定轨道移动
        if (!this.forceTrackTarget || this.forceTrackTarget.death) {
            this.trackData = null;
            return false;
        }

        if (this.draw_fixedTrack_gravity_Line) {
            UICtrl.LineRenderer(this.unitWorldPos, this.forceTrackTarget.unitWorldPos, Color.WHITE, Drawlayer.Game);
        }

        if (this.fixedTrackInterval > 0) {
            this.fixedTrackInterval -= dt;
            if (!this.trackData) {//间隔内只能获取一次轨道数据
                return false;
            }
        }
        //超过一个大质量天体的影响 且 捕获来源没有开启同步轨道功能
        if (this._bigPlanetCount > 1 && !this.forceTrackTarget.oneTrack) {
            this.forceTrackTarget.RemoveSatellite(this);
            return false;
        }

        this.standTime = 1;
        // this.forceTrackTarget.oneTrack = true;
        if (!this.forceTrackTarget.oneTrack) {//是否已满
            let space = this.collider.radius * 2;//轨道间隔
            let maxTrackNum = Math.min(20, this.forceTrackTarget.alertFieldRadius / space);
            if (this.forceTrackTarget.satellitesMap.size > maxTrackNum) {
                return false;
            }
        }
        //没有被捕获过 且 只受一个大质量天体影响
        if (!this.trackData && this.bigStarCount < 2) {
            this.checkFixedTrackCapture(
                this.forceTrackTarget.oneTrack,
                this.forceTrackTarget.track_circle_priority);
        }

        if (!this.trackData || this.playerCtrl) {//不能锁定玩家
            return false;
        }
        //不断通过切线方向计算出下一帧应该旋转到的位置
        let radiusVector = this.ToVec2(this.forceTrackTarget.GetDirToOther(this));
        let targetPos = this.forceTrackTarget.unitWorldPos;

        let tangentDirection: Vec2 = new Vec2(-radiusVector.y * this.trackData.rotationDir,
            this.trackData.rotationDir * radiusVector.x).normalize();
        // let tangentDirection: Vec2 = new Vec2(-radiusVector.y, radiusVector.x).normalize();
        let radiusDirection = this.ToVec3(radiusVector).normalize();
        tangentDirection.multiplyScalar(this.trackData.linearV)//这个可以直接修改环绕速度，不用乘物理帧间隔时间了

        let parentV = this.forceTrackTarget.rigBody.linearVelocity.clone();
        tangentDirection.add(parentV);//加上目标速度

        targetPos = targetPos.add(radiusDirection.clone().multiplyScalar(this.trackData.circleRadius));
        targetPos.add(this.ToVec3(tangentDirection));

        //this.trackData.linearV是linearVelocity计算出来的，并且是覆盖不是累加就不用再乘帧率了
        this.MoveTo(targetPos, true);//如果只有一个大型天体 移动到该位置覆盖其速度

        this.parentUnit = this.forceTrackTarget;

        return true;
    }

    /**检测轨道位置捕获  */
    private checkFixedTrackCapture(oneTrack: boolean = false, circle_priority = 0): boolean {

        //公用一个轨道
        if (oneTrack && this.forceTrackTarget.satellitesMap.size > 0) {
            let first_satellite: UnitPlanetBase = null; //找到符合该卫星的轨道
            for (let satellite of this.forceTrackTarget.satellitesMap.keys()) {

                if (satellite.collider.radius == this.collider.radius) {
                    first_satellite = satellite;
                    break;
                }
            }
            if (first_satellite == null) {
                //没有换条轨道
                return this.checkFixedTrackCapture(false, circle_priority);
            }
            let first_track = this.forceTrackTarget.satellitesMap.get(first_satellite);

            let curCircleRaduis = this.GetDirToOther(this.forceTrackTarget).length();
            let track = this.forceTrackTarget
                .CalculateCircleTrackData(this, first_track.circleRadius - curCircleRaduis);
            //轨道半径相近
            if (Math.floor(first_track.circleRadius) != Math.floor(track.circleRadius)) {

                return false;
            }
            // 计算轨道的周长 2Πr
            let trackCircumference = 2 * Math.PI * track.circleRadius;
            // 可放置卫星数
            let max_count: number = Math.floor(trackCircumference / (this.collider.radius * 2));//该轨道最多拥有卫星
            if (this.forceTrackTarget.satellitesMap.size >= max_count) {
                return false;
            }
            // 计算每个卫星之间的弧度间隔 PI = 180角度
            let angleInterval = 2 * Math.PI / max_count;

            // 遍历已有的卫星，检查是否有重叠的情况
            for (let satellite of this.forceTrackTarget.satellitesMap.keys()) {
                // 获取当前卫星与已有卫星之间的方向矢量
                let currentSatelliteVector = this.forceTrackTarget.GetDirToOther(this);  // 当前卫星的方向矢量
                let existingSatelliteVector = this.forceTrackTarget.GetDirToOther(satellite); // 已有卫星的方向矢量

                // 计算两个方向矢量之间的角度差（通过点积计算夹角）
                let dotProduct = currentSatelliteVector.dot(existingSatelliteVector);
                let magnitudeProduct = currentSatelliteVector.length() * existingSatelliteVector.length();
                let angleBetweenSatellites = Math.acos(dotProduct / magnitudeProduct); // 计算两个向量的夹角弧度

                // 如果卫星之间的弧度小于允许的弧度间隔，则认为重叠
                if (angleBetweenSatellites < angleInterval) {
                    return false; // 重叠，捕获失败
                }
            }

            //速度和方向保持一致
            track.rotationDir = first_track.rotationDir;
            track.linearV = first_track.linearV;

            this.forceTrackTarget.AddSatellite(this, track);
            return true;
        }
        else {
            let curCircleRaduis = this.GetDirToOther(this.forceTrackTarget).length();
            let track: PlanetTrackData = null;

            let all_satellites_track_data = Array.from(this.forceTrackTarget.satellitesMap.values());

            let hasCirclePos = false;
            let while_max_count = this.forceTrackTarget.alertFieldRadius / 10;//轨道间隔最小10
            if (circle_priority == -1) {//内圈优先
                //上次比较的轨道半径
                let last_s_r = this.forceTrackTarget.collider.radius;
                all_satellites_track_data.sort((track_a, track_b) => {
                    return track_a.circleRadius - track_b.circleRadius;
                });
                while (while_max_count > 0) {
                    while_max_count--;
                    hasCirclePos = true;
                    //当前预备轨道半径
                    let cur_track_radius = this.collider.radius + last_s_r;
                    if (cur_track_radius >= this.forceTrackTarget.alertFieldRadius) {
                        hasCirclePos = false;
                        break;
                    }
                    for (let track_data of all_satellites_track_data) {
                        if (Math.abs(track_data.circleRadius - cur_track_radius)
                            < track_data.planet.collider.radius + this.collider.radius) {
                            hasCirclePos = false;
                            last_s_r = track_data.circleRadius + track_data.planet.collider.radius;
                            break;
                        }
                    }
                    if (hasCirclePos) {
                        let offset = curCircleRaduis - cur_track_radius - 3;//每个再间隔3
                        track = this.forceTrackTarget.CalculateCircleTrackData(this, -offset);
                        break;
                    }
                }
            }
            else if (circle_priority == 1) {//外圈优先
                //上次比较的轨道半径
                let last_s_r = this.forceTrackTarget.alertFieldRadius;
                all_satellites_track_data.sort((track_a, track_b) => {
                    return track_b.circleRadius - track_a.circleRadius;
                });
                while (while_max_count > 0) {
                    while_max_count--;
                    hasCirclePos = true;
                    //当前预备轨道半径
                    let cur_track_radius = last_s_r - this.collider.radius;
                    if (cur_track_radius <= this.forceTrackTarget.collider.radius + this.collider.radius) {
                        hasCirclePos = false;
                        break;
                    }
                    for (let track_data of all_satellites_track_data) {
                        if (Math.abs(track_data.circleRadius - cur_track_radius)
                            < track_data.planet.collider.radius + this.collider.radius) {
                            hasCirclePos = false;
                            last_s_r = track_data.circleRadius - track_data.planet.collider.radius;
                            break;
                        }
                    }
                    if (hasCirclePos) {
                        let offset = curCircleRaduis - cur_track_radius - 1;
                        track = this.forceTrackTarget.CalculateCircleTrackData(this, -offset);
                        break;
                    }
                }
            }
            else {//就近优先
                let offset = curCircleRaduis > this.forceTrackTarget.alertFieldRadius ? -50 : 0;
                track = this.forceTrackTarget.CalculateCircleTrackData(this, offset);
                let remain_radius = this.forceTrackTarget.alertFieldRadius;
                for (let satellite of this.forceTrackTarget.satellitesMap.keys()) {
                    remain_radius -= satellite.collider.radius * 2;
                }
                hasCirclePos = this.collider.radius * 2 < remain_radius;//有空位
                this.forceTrackTarget.satellitesMap.forEach((trackData, satellite) => {
                    // 存在和某个卫星距离太近就无法入轨
                    if (Math.abs(trackData.circleRadius - track.circleRadius)
                        < (satellite.collider.radius + this.collider.radius)) {
                        hasCirclePos = false;
                    }
                });
            }
            if (hasCirclePos) {
                // this.trackData = track;
                this.forceTrackTarget.AddSatellite(this, track);
                // console.log('捕获速度', this.trackData.linearV)

                return true;
            }
        }

        return false;
    }

    /**计算小于目标单位的天体对着自己的引力影响 */
    protected UpdateSmallerTargetPlanetForce(type?: UnitType, ignoreForceTrackTarget = true) {
        type = type || this.unitType;
        let smallerPlanets = this.FilterOtherImpactPlanet_All((planet) => {
            if (planet.unitType < type) {
                if (ignoreForceTrackTarget && this == planet) {
                    return false;
                }
                return true;
            }
            return false;
        });

        this.UpdateOtherPlanetForce(smallerPlanets);
    }

    /**计算大于目标单位的天体对着自己的引力影响 */
    protected UpdateBiggerTargetPlanetForce(type?: UnitType, ignoreForceTrackTarget = true) {
        type = type || this.unitType;
        let smallerPlanets = this.FilterOtherImpactPlanet_All((planet) => {
            if (planet.unitType > type) {
                if (ignoreForceTrackTarget && this == planet) {
                    return false;
                }
                return true;
            }
            return false;
        });

        this.UpdateOtherPlanetForce(smallerPlanets);
    }

    /**捕获计算 */
    protected CalculateCircleTrackData(planet: UnitPlanetBase, radiusAdjust: number = 0): PlanetTrackData {
        //加入轨道分级设定、否则每次捕获都在同一轨道、会经常发生撞击。

        // 计算向心加速度
        let radiusVector: Vec2 = this.ToVec2(this.GetDirToOther(planet)); // 从圆心到当前位置的向量

        if (planet.unitType == UnitType.UnitSun && this.unitType == UnitType.UnitSun) {//如果对方也是恒星，按质量比分配之间的速度影响
            let sumMass = this.mass + planet.mass;
            radiusVector.multiplyScalar(this.mass / sumMass);
        }

        let radius = radiusVector.length() + radiusAdjust;

        radius = Math.max(0, radius);

        let gravity = this.CalculateGravityWithOther(planet);
        // 计算切线方向的单位向量
        let tangentDirection: Vec2 = new Vec2(-radiusVector.y, radiusVector.x).normalize();
        let planetV = planet.rigBody.linearVelocity.normalize();
        let cos = planetV.dot(tangentDirection.clone());
        if (cos < 0) {//切线反了
            tangentDirection.multiplyScalar(-1);
            if (sys.isBrowser && <UnitPlanet>planet == Global.gameManager.playerUnit) {
                // GameEventMgr.Dispatch(GameEvent.LogGameMessage, '捕获方向反向！')
            }
        }

        // 计算切线速度
        let tangentVelocity: Vec2 = tangentDirection.multiplyScalar(Math.sqrt(gravity * radius));
        //除5才能接近正确的线速度，也不知为什么，应该是游戏距离单位和现实不一致参与引力计算时需要缩放调整
        let linearV = tangentVelocity.length() * 0.2;// * 0.2;

        return {
            planet: planet,
            circleRadius: radius,
            circleGravity: gravity,
            linearV: linearV,//返回速度是每秒单位，对应到帧要乘物理间隔帧
            rotationDir: cos < 0 ? -1 : 1,
        };
    }

    //每帧外力施加汇总
    protected _RBVFrame_MoveAdd: Vec2 = new Vec2;
    //每帧引力施加汇总
    protected _RBVFrame_GravityAdd: Vec2 = new Vec2;
    /**
     * 给行星单位施加一个到某个方向的力，若速度超过最大设定速度、则只有分量作效
     * @param worldPos 世界坐标
     */
    public MoveToWeightDt(worldPos: Vec3): Vec2 {
        let moveDir = worldPos.clone().subtract(this.unitWorldPos);

        return this.MoveToWeightDt_byDir(moveDir);
    }

    public MoveToWeightDt_byDir(dir: Vec3): Vec2 {
        let moveDir = this.ToVec2(dir).normalize();
        let selfVec = this.rigBody.linearVelocity.normalize();

        let cos = selfVec.dot(moveDir.clone().normalize())
        //速度方向上的分量
        let velocityVec = selfVec.clone().multiplyScalar(cos);
        //垂直方向上的分量
        let tangentVec = moveDir.clone().subtract(velocityVec);

        let scale = this.moveAcceleration;
        scale *= PhysicsSystem2D.instance.fixedTimeStep;
        if (this.speed < this.maxSpeed) {//这里小于时又突然加速了 应该再乘个帧率
            // this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(moveDir.multiplyScalar(scale));
            this._RBVFrame_MoveAdd.add(moveDir.multiplyScalar(scale));

            this.standTime = 1;
        }
        else {
            scale = this.moveAcceleration;
            scale *= PhysicsSystem2D.instance.fixedTimeStep;
            //超过最大速度、只用分量
            // this.rigBody.linearVelocity = this.rigBody.linearVelocity.add(tangentVec.multiplyScalar(scale));

            this._RBVFrame_MoveAdd.add(tangentVec.multiplyScalar(scale));

        }

        return moveDir;
    }

    /**
     * 给行星单位施加一个到某个位置的力
     * @param worldPos 世界坐标
     * @param ignoreLinearVelocity 忽略本身速度影响，会覆盖原本的速度，如果没有给moveAc，坐标距离会影响速度
     */
    public MoveTo(worldPos: Vec3, ignoreLinearVelocity: boolean = false): Vec2 {
        // 计算物体需要移动的距离和方向
        let moveDir = worldPos.clone().subtract(this.unitWorldPos);

        return this.MoveTo_byDir(moveDir, ignoreLinearVelocity, moveDir.length());
    }

    /**
     * 给行星单位施加一个到某个方向的力
     * @param dir 方向
     * @param ignoreLinearVelocity 忽略本身速度影响，会覆盖原本的速度，如果没有给moveAc，坐标距离会影响速度
     * @param moveAc 提供移动加速度，没有会使用自身的
     */
    public MoveTo_byDir(dir: Vec3, ignoreLinearVelocity: boolean = false, moveAc?: number): Vec2 {

        this.standTime = 1;
        let moveDir = this.ToVec2(dir);

        if (ignoreLinearVelocity) {
            if (moveAc) {
                let v = moveDir.normalize().multiplyScalar(moveAc);
                // this._RBVFrame_MoveAdd = v;//不能汇总，不然不就累加了吗
                this.rigBody.linearVelocity = v;
            }
            else {
                let v = moveDir.normalize().multiplyScalar(this.moveAcceleration);
                // this._RBVFrame_MoveAdd = v;
                this.rigBody.linearVelocity = v;
            }

            // return this._RBVFrame_MoveAdd.length();
            // return this.rigBody.linearVelocity.length();
            return moveDir;
        }
        else {

            let v = moveDir.normalize();
            if (moveAc) {
                v.multiplyScalar(moveAc);
            }
            else {
                v.multiplyScalar(this.moveAcceleration);
            }
            let addSpeed = this._RBVFrame_MoveAdd.add(v);

            // this.rigBody.linearVelocity = addSpeed;

            // return addSpeed.length();
            return moveDir;
        }
    }

    /**刹车 减速系数 最低速度 */
    public Stand(dt: number, friction: number = 0.1, minSpeed: number = 0) {
        if (this.speed > minSpeed) {

            this.rigBody.linearVelocity = this.rigBody.linearVelocity.multiplyScalar(this.standTime);
        }
        else {
            this.standTime = 0;
        }
        this.standTime -= PhysicsSystem2D.instance.fixedTimeStep * friction;
        this.standTime = Math.max(0, this.standTime);
        //指数衰减 100减少到10只需2.3秒
        this._frameMaxSpeed = this._frameMaxSpeed > 1 ? this._frameMaxSpeed * (1 - PhysicsSystem2D.instance.fixedTimeStep) : 0;
    }

    private _target_velocity_vec: Vec3 = new Vec3;
    private _self_velocity_vec: Vec3 = new Vec3;
    /**计算该恒星对目标星球的洛希极限距离 */
    public CalculateRocheLimitWithTarget(target: UnitPlanetBase) {
        if (this.unitType < UnitType.UnitSun) {
            return 0;
        }
        let trackData = this.CalculateCircleTrackData(target);
        let standrad_circumferential_velocity = trackData.linearV; //正常环绕速度

        let target_velocity_v2 = target.rigBody.linearVelocity.clone();
        this._target_velocity_vec.set(target_velocity_v2.x, target_velocity_v2.y);

        let self_velocity_v2 = this.rigBody.linearVelocity.clone();
        this._self_velocity_vec.set(self_velocity_v2.x, self_velocity_v2.y);

        // 计算相对速度
        let relative_velocity_vec = this._target_velocity_vec.subtract(this._self_velocity_vec); // 相对速度向量
        let relative_velocity = relative_velocity_vec.length(); // 相对速度标量
        let relative_velocity_normalize = relative_velocity_vec.clone().normalize();

        let g_dir = target.GetDirToOther(this);
        let g_dir_normalize = g_dir.clone().normalize();

        let gravity_sun = this.CalculateGravityWithOther(target);
        let gravity_planet = target.CalculateGravityWithOther(this);

        let gravity = gravity_sun + gravity_planet;
        let gravityF = gravity_sun * target.mass + gravity_planet * this.mass; // 引力大小

        // 初始化其他恒星引力对环绕速度和当前恒星引力的影响
        let extra_velocity_from_others = 0; // 其他恒星的引力对目标速度的额外贡献
        let gravityF_from_others = 0; // 其他恒星在引力方向上的分量贡献
        let otherStars = target.FilterOtherImpactPlanet_All((planet) => {
            return planet.unitType >= UnitType.UnitSun && planet != this;
        })
        for (let star of otherStars) {

            let star_gravity_vec = target.GetDirToOther(star).normalize().multiplyScalar(
                star.CalculateGravityWithOther(target) * target.mass
            );

            // 分解其他恒星的引力分量
            let circumferential_component = star_gravity_vec.dot(relative_velocity_normalize); // 对目标速度的贡献
            let gravity_component = star_gravity_vec.dot(g_dir_normalize); // 对当前恒星引力方向的贡献

            // 更新额外环绕速度和引力
            extra_velocity_from_others += circumferential_component;
            gravityF_from_others += gravity_component;

            // 检查引力方向是否颠倒
            let total_gravity_dir = g_dir.clone().multiplyScalar(gravityF + gravityF_from_others).normalize();
            if (total_gravity_dir.dot(g_dir_normalize) < 0) {
                return 0; // 引力方向颠倒，当前恒星无法维持洛希极限
            }
        }

        //汇总相对速度的影响
        relative_velocity += extra_velocity_from_others;

        let cos_velocity_with_gravity = g_dir_normalize.dot(relative_velocity_normalize);
        let sin_velocity_with_gravity = Math.sqrt(1 - cos_velocity_with_gravity * cos_velocity_with_gravity);

        let target_circumferential_velocity = sin_velocity_with_gravity * relative_velocity; //当前在环绕方向上的速度
        let target_gravity_weight_velocity = cos_velocity_with_gravity * relative_velocity;  //当前朝向恒星方向上的分量速度

        //维持环绕轨道后额外的环绕动量
        let extra_circumferential_velocity = target_circumferential_velocity - standrad_circumferential_velocity;
        //需要克服的引力方向上的动量  速度越是靠近环绕方向，需要克服的引力越小
        let gravity_sum_velocity = target_gravity_weight_velocity + Math.abs(cos_velocity_with_gravity) * gravityF;
        //额外的逃逸速度？
        let extra_velocity = relative_velocity - gravity_sum_velocity;
        //行星引擎可提供的最大动量
        let engine_velocity = target.moveAcceleration;
        //可额外抵消引力
        let restrain_num = extra_circumferential_velocity + engine_velocity + extra_velocity;
        //距离可代替引力势能加入引力抵消计算中
        // let distance = this.DistanceOther(target);
        // let distance_velocity = Math.sqrt(gravity * distance) * 0.2;
        // let distance_velocity = distance * gravity * PhysicsSystem2D.instance.fixedTimeStep * 1.38;
        restrain_num = restrain_num + standrad_circumferential_velocity;

        let G = 667.4;
        let F = gravityF + restrain_num;//极限引力
        let r = this.alertFieldRadius;
        if (F > 0) {
            r = Math.sqrt(G * this.mass * target.mass / F);
        }

        return Math.min(r, this.alertFieldRadius); //极限圈
    }

    protected onColliderEnter(selfCollider: Collider2D, otherCollider: Collider2D) {
        super.onColliderEnter(selfCollider, otherCollider);
        let other = otherCollider.node.getComponent(UnitPlanetBase);

        if (otherCollider.sensor) {
            //console.log("啊我被发现了！");
        }
        else {
            // console.log("啊我被撞了！");
            if (other.unitType > this.unitType) {
                // this.node.destroy();//还不能碰撞立即销毁

                if (!this.already_initialized) {//碰撞事件比update先，有可能碰撞发生时，目标_destroy还没重置
                    //给个速度让其离开碰撞区域
                    let dir = this.unitWorldPos.subtract(other.unitWorldPos);
                    this.MoveTo_byDir(dir, true, 500);//给个反向速度
                }
                this.DestroySelf("被大质量星体撞毁！");

                let dir = other.unitWorldPos.subtract(this.unitWorldPos);
                other.MoveTo_byDir(dir, false, 10 * this.mass / other.mass);//给个反向速度

            }
            else if (other.unitType == this.unitType) {
                let remain = this.mass - other.mass;
                if (remain <= 0) {
                    if (!this.already_initialized) {//碰撞事件比update先，有可能碰撞发生时，目标_destroy还没重置
                        //给个速度让其离开碰撞区域
                        let dir = this.unitWorldPos.subtract(other.unitWorldPos);
                        this.MoveTo_byDir(dir, true, 500);//给个反向速度
                    }
                    this.DestroySelf("被星体撞击丢失维持自身的最低质量！");
                }
                else {
                    let dir = this.unitWorldPos.subtract(other.unitWorldPos);
                    this.MoveTo_byDir(dir, true, 500);//给个反向速度
                    this.mass = remain;
                }
            }
        }

    }

    protected onTriggerEnter(selfCollider: Collider2D, otherCollider: Collider2D) {
        super.onTriggerEnter(selfCollider, otherCollider);
        // 只在两个碰撞体开始接触时被调用一次
        let other = otherCollider.node.getComponent(UnitPlanetBase);

        if (other) {
            other.AddPlanetGravityImpact(this);
        }
    }

    protected onTriggerExit(selfCollider: Collider2D, otherCollider: Collider2D) {
        super.onTriggerExit(selfCollider, otherCollider);
        let other = otherCollider.node.getComponent(UnitPlanetBase);

        if (other) {
            other.RemovePlanetGravityImpact(this);
        }
    }
}